The addresses 2643866716704 to 2643866716712 are of special interest to us. The first address is the
address of our stack pointer, the value we write to the rsp register of the CPU. The range represents
the values we wrote to the stack before we made the switch.
NOTE
The actual addresses you get will be different every time you run the program.
In other words, the values 240, 205, 252, 56, 67, 86, 0, 0 represent the pointer to our hello()
function written as u8 values.
ENDIANNESS
An interesting side note here is that the order the CPU writes an u64 as a set of 8 u8 bytes is dependent on its
endianness. In other words, a CPU can write our pointer address as 240, 205, 252, 56, 67, 86, 0, 0 if it’s little-
endian or 0, 0, 86, 67, 56, 252, 205, 240 if it’s big-endian. Think of it like how Hebrew, Arabic, and Persian
languages read and write from right to left, while Latin, Greek, and Indic languages read and write from left to right. It
doesn’t really matter as long as you know it in advance, and the results will be the same.
The x86-64 architecture uses a little-endian format, so if you try to parse the data manually, you’ll have to bear this in mind.
As we write more complex functions, our extremely small 48-byte stack will soon run out of space.
You see, as we run the functions we write in Rust, the CPU will now push and pop values on our new
stack to execute our program and it’s left to the programmer to make sure they don’t overflow the
stack. This brings us to our next topic: stack sizes.
Stack sizes
We touched upon this topic earlier in Chapter 2, but now that we’ve created our own stack and made
our CPU jump over to it, you might get a better sense of the issue. One of the advantages of creating
our own green threads is that we can freely choose how much space we reserve for each stack.
When you start a process in most modern operating systems, the standard stack size is normally 8
MB, but it can be configured differently. This is enough for most programs, but it’s up to the
programmer to make sure we don’t use more than we have. This is the cause of the dreaded stack
overflow that most of us have experienced.
However, when we can control the stacks ourselves, we can choose the size we want. 8 MB for each
task is way more than we need when running simple functions in a web server, for example, so by
reducing the stack size, we can have millions of fibers/green threads running on a machine. We run
out of memory a lot sooner using stacks provided by the operating system.
Anyway, we need to consider how to handle the stack size, and most production systems such as
Boost.Coroutine or the one you find in Go will use either segmented stacks or growable stacks. We
will make this simple for ourselves and use a fixed stack size going forward.